
/**
 * @file Synchronize.cpp
 * This class synchronizes two GNSS Data Structures data streams.
 */

#include "Synchronize.hpp"

using namespace std;

namespace gpstk
{

      // Return a string identifying this object.
   std::string Synchronize::getClassName() const
   { return "Synchronize"; }



      /* Sets tolerance, in seconds.
       *
       * @param tol                 Tolerance, in seconds.
       */
   Synchronize& Synchronize::setTolerance(const double tol)
   {

         // Make sure that tolerance is positive
      if( tol >= 0.0 )
      {
         tolerance = tol;
      }

      return (*this);

   }  // End of method 'Synchronize::setTolerance()'



      /* Return a gnnsRinex object, adding the new data generated
       * when calling this object.
       *
       * @param gData    Data object holding the data.
       */
   void Synchronize::Process(commonHeader& comHeader, gnssRinex& gData)
      noexcept(false)
   {
      CommonTime time = dynamic_cast<gnssRinex*>(pgRov1)->header.epoch;
      Process(time,gData);

   }  // End of method 'Synchronize::Process()'



   gnssRinex& Synchronize::Process(CommonTime time, gnssRinex& gData)
      noexcept(false)
   {

      if (firstTime)
      {
         (*pRinexRef) >> gData;      // Get data out of ref station RINEX file

         gnssRinexBuffer.clear();
         gnssRinexBuffer.push_back(gData);

         firstTime = false;          // Mark that first data batch was read
      }

      gData = gnssRinexBuffer.front();

//      cout << gData.header.source << endl;

      if( (gData.header.epoch > time) &&
          (std::abs( gData.header.epoch - time ) > tolerance) )
      {
         // If synchronization is not possible, we issue an exception
         SynchronizeException e( "Unable to synchronize data at epoch "
            + time.asString() );
         GPSTK_THROW(e);
      }

      // Check that the reference data time stamp is not less than gData's,
      // and that tolerance is within limits. If not, keep reading.
      // Note that if reference data time stamp is bigger, it will not
      // enter here, "waiting" for gData to catch up.

      streampos sp = pRinexRef->tellg();

      while ( ( gData.header.epoch < time ) &&
              (std::abs( gData.header.epoch - time ) > tolerance) )
      {
          if( (*pRinexRef).eof() ) break;

          if( gData.header.epoch == time ) break;

          (*pRinexRef) >> gData;   // Get data out of ref station RINEX file
      }

      if( gData.header.epoch > time ) pRinexRef->seekg(sp);

//      cout << CivilTime(gData.header.epoch)
//           << endl
//           << CivilTime(time)
//           << endl
//           << endl;

      // If we couldn't synchronize data streams (i.e.: "tolerance"
      // is not met), skip this epoch.
      if ( std::abs( gData.header.epoch - time ) > tolerance )
      {
         // If synchronization is not possible, we issue an exception
         SynchronizeException e( "Unable to synchronize data at epoch "
            + time.asString() );
         GPSTK_THROW(e);
      }

      return gData;

   }  // End of method 'Synchronize::Process(CommonTime time, gnssRinex& gData)'

}  // End of namespace gpstk
